


using System;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using SubSonic.DataProviders;
using SubSonic.Extensions;
using SubSonic.Linq.Structure;
using SubSonic.Query;
using SubSonic.Schema;
using System.Data.Common;
using System.Collections.Generic;

namespace V5_EShop.Data
{
    public partial class BookEShopDB : IQuerySurface
    {

        public IDataProvider DataProvider;
        public DbQueryProvider provider;
        
        public static IDataProvider DefaultDataProvider { get; set; }

        public bool TestMode
		{
            get
			{
                return DataProvider.ConnectionString.Equals("test", StringComparison.InvariantCultureIgnoreCase);
            }
        }

        public BookEShopDB() 
        {
            if (DefaultDataProvider == null) {
                DataProvider = ProviderFactory.GetProvider("V5_EBook");
            }
            else {
                DataProvider = DefaultDataProvider;
            }
            Init();
        }

        public BookEShopDB(string connectionStringName)
        {
            DataProvider = ProviderFactory.GetProvider(connectionStringName);
            Init();
        }

		public BookEShopDB(string connectionString, string providerName)
        {
            DataProvider = ProviderFactory.GetProvider(connectionString,providerName);
            Init();
        }

		public ITable FindByPrimaryKey(string pkName)
        {
            return DataProvider.Schema.Tables.SingleOrDefault(x => x.PrimaryKey.Name.Equals(pkName, StringComparison.InvariantCultureIgnoreCase));
        }

        public Query<T> GetQuery<T>()
        {
            return new Query<T>(provider);
        }
        
        public ITable FindTable(string tableName)
        {
            return DataProvider.FindTable(tableName);
        }
               
        public IDataProvider Provider
        {
            get { return DataProvider; }
            set {DataProvider=value;}
        }
        
        public DbQueryProvider QueryProvider
        {
            get { return provider; }
        }
        
        BatchQuery _batch = null;
        public void Queue<T>(IQueryable<T> qry)
        {
            if (_batch == null)
                _batch = new BatchQuery(Provider, QueryProvider);
            _batch.Queue(qry);
        }

        public void Queue(ISqlQuery qry)
        {
            if (_batch == null)
                _batch = new BatchQuery(Provider, QueryProvider);
            _batch.Queue(qry);
        }

        public void ExecuteTransaction(IList<DbCommand> commands)
		{
            if(!TestMode)
			{
                using(var connection = commands[0].Connection)
				{
                   if (connection.State == ConnectionState.Closed)
                        connection.Open();
                   
                   using (var trans = connection.BeginTransaction()) 
				   {
                        foreach (var cmd in commands) 
						{
                            cmd.Transaction = trans;
                            cmd.Connection = connection;
                            cmd.ExecuteNonQuery();
                        }
                        trans.Commit();
                    }
                    connection.Close();
                }
            }
        }

        public IDataReader ExecuteBatch()
        {
            if (_batch == null)
                throw new InvalidOperationException("There's nothing in the queue");
            if(!TestMode)
                return _batch.ExecuteReader();
            return null;
        }
			
        public Query<ModelUserToArea> ModelUserToAreas { get; set; }
        public Query<ModelUserRole> ModelUserRoles { get; set; }
        public Query<ModelB_BookClass> ModelB_BookClasses { get; set; }
        public Query<ModelUser> ModelUsers { get; set; }
        public Query<ModelB_BookTopicClass> ModelB_BookTopicClasses { get; set; }
        public Query<ModelShop_Cart> ModelShop_Carts { get; set; }
        public Query<ModelArticleComment> ModelArticleComments { get; set; }
        public Query<ModelB_BookComment> ModelB_BookComments { get; set; }
        public Query<ModelShop_Payment> ModelShop_Payments { get; set; }
        public Query<ModelShop_Shipment> ModelShop_Shipments { get; set; }
        public Query<ModelShop_Order> ModelShop_Orders { get; set; }
        public Query<ModelShop_OrderProduct> ModelShop_OrderProducts { get; set; }
        public Query<ModelB_Book> ModelB_Books { get; set; }
        public Query<ModelFriend> ModelFriends { get; set; }
        public Query<ModelHotKeyWord> ModelHotKeyWords { get; set; }
        public Query<ModelHelpClass> ModelHelpClasses { get; set; }
        public Query<ModelHelp> ModelHelps { get; set; }
        public Query<ModelB_BookPublish> ModelB_BookPublishes { get; set; }
        public Query<ModelB_BookAuthor> ModelB_BookAuthors { get; set; }
        public Query<ModelBlocker> ModelBlockers { get; set; }
        public Query<ModelConfig> ModelConfigs { get; set; }
        public Query<ModelArticleClass> ModelArticleClasses { get; set; }
        public Query<ModelArticle> ModelArticles { get; set; }
        public Query<ModelAdmin> ModelAdmins { get; set; }
        public Query<ModelB_BookIsbn> ModelB_BookIsbns { get; set; }
        public Query<ModelFriendClass> ModelFriendClasses { get; set; }
        public Query<ModelShop_Area> ModelShop_Areas { get; set; }
        public Query<ModelHotKeyWordClass> ModelHotKeyWordClasses { get; set; }
        public Query<ModelAdminRole> ModelAdminRoles { get; set; }
        public Query<ModelArticleTopicClass> ModelArticleTopicClasses { get; set; }

			

        #region ' Aggregates and SubSonic Queries '
        public Select SelectColumns(params string[] columns)
        {
            return new Select(DataProvider, columns);
        }

        public Select Select
        {
            get { return new Select(this.Provider); }
        }

        public Insert Insert
		{
            get { return new Insert(this.Provider); }
        }

        public Update<T> Update<T>() where T:new()
		{
            return new Update<T>(this.Provider);
        }

        public SqlQuery Delete<T>(Expression<Func<T,bool>> column) where T:new()
        {
            LambdaExpression lamda = column;
            SqlQuery result = new Delete<T>(this.Provider);
            result = result.From<T>();
            result.Constraints=lamda.ParseConstraints().ToList();
            return result;
        }

        public SqlQuery Max<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = DataProvider.FindTable(objectName).Name;
            return new Select(DataProvider, new Aggregate(colName, AggregateFunction.Max)).From(tableName);
        }

        public SqlQuery Min<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Min)).From(tableName);
        }

        public SqlQuery Sum<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Sum)).From(tableName);
        }

        public SqlQuery Avg<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Avg)).From(tableName);
        }

        public SqlQuery Count<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Count)).From(tableName);
        }

        public SqlQuery Variance<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Var)).From(tableName);
        }

        public SqlQuery StandardDeviation<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.StDev)).From(tableName);
        }

        #endregion

        void Init()
        {
            provider = new DbQueryProvider(this.Provider);

            #region ' Query Defs '
            ModelUserToAreas = new Query<ModelUserToArea>(provider);
            ModelUserRoles = new Query<ModelUserRole>(provider);
            ModelB_BookClasses = new Query<ModelB_BookClass>(provider);
            ModelUsers = new Query<ModelUser>(provider);
            ModelB_BookTopicClasses = new Query<ModelB_BookTopicClass>(provider);
            ModelShop_Carts = new Query<ModelShop_Cart>(provider);
            ModelArticleComments = new Query<ModelArticleComment>(provider);
            ModelB_BookComments = new Query<ModelB_BookComment>(provider);
            ModelShop_Payments = new Query<ModelShop_Payment>(provider);
            ModelShop_Shipments = new Query<ModelShop_Shipment>(provider);
            ModelShop_Orders = new Query<ModelShop_Order>(provider);
            ModelShop_OrderProducts = new Query<ModelShop_OrderProduct>(provider);
            ModelB_Books = new Query<ModelB_Book>(provider);
            ModelFriends = new Query<ModelFriend>(provider);
            ModelHotKeyWords = new Query<ModelHotKeyWord>(provider);
            ModelHelpClasses = new Query<ModelHelpClass>(provider);
            ModelHelps = new Query<ModelHelp>(provider);
            ModelB_BookPublishes = new Query<ModelB_BookPublish>(provider);
            ModelB_BookAuthors = new Query<ModelB_BookAuthor>(provider);
            ModelBlockers = new Query<ModelBlocker>(provider);
            ModelConfigs = new Query<ModelConfig>(provider);
            ModelArticleClasses = new Query<ModelArticleClass>(provider);
            ModelArticles = new Query<ModelArticle>(provider);
            ModelAdmins = new Query<ModelAdmin>(provider);
            ModelB_BookIsbns = new Query<ModelB_BookIsbn>(provider);
            ModelFriendClasses = new Query<ModelFriendClass>(provider);
            ModelShop_Areas = new Query<ModelShop_Area>(provider);
            ModelHotKeyWordClasses = new Query<ModelHotKeyWordClass>(provider);
            ModelAdminRoles = new Query<ModelAdminRole>(provider);
            ModelArticleTopicClasses = new Query<ModelArticleTopicClass>(provider);
            #endregion


            #region ' Schemas '
        	if(DataProvider.Schema.Tables.Count == 0)
			{
            	DataProvider.Schema.Tables.Add(new ModelUserToAreaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelUserRoleTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelB_BookClassTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelUserTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelB_BookTopicClassTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelShop_CartTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelArticleCommentTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelB_BookCommentTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelShop_PaymentTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelShop_ShipmentTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelShop_OrderTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelShop_OrderProductTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelB_BookTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelFriendTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelHotKeyWordTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelHelpClassTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelHelpTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelB_BookPublishTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelB_BookAuthorTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelBlockerTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelConfigTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelArticleClassTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelArticleTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelAdminTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelB_BookIsbnTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelFriendClassTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelShop_AreaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelHotKeyWordClassTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelAdminRoleTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ModelArticleTopicClassTable(DataProvider));
            }
            #endregion
        }
        

        #region ' Helpers '
            
        internal static DateTime DateTimeNowTruncatedDownToSecond() {
            var now = DateTime.Now;
            return now.AddTicks(-now.Ticks % TimeSpan.TicksPerSecond);
        }

        #endregion

    }
}